package com.moleq.device;

import java.io.IOException;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import jp.co.casio.caios.framework.device.LinePrinter;
import jp.co.casio.caios.framework.device.lineprintertools.BuildinEx840;
import jp.co.casio.caios.framework.device.lineprintertools.LinePrinterDeviceBase;

import com.moleq.util.StringUtils;

public class CasioPrinter implements IPrinter {

	protected int iTotalLen = 46;
	public final static int FONT_SINGLE_SIZE = 0;
	public final static int FONT_DOUBLE_SIZE = 1;
	public final static int FONT_DOUBLE_HEIGHT = 2;
	
	public final static int LEFT = 10;
	public final static int CENTER = 20;
	public final static int RIGHT = 30;
	
	
	private final static char[] ESC_BASE_CH	= {0x1B, '|'};
	private final static char[] LINEFEED_CH = {'\n'};
	private final static char ESC_CANCEL = '!';

	private final static String ESC_BASE		= CharBuffer.wrap(ESC_BASE_CH).toString();
	private final static String PAPER_CUT		= "P";
	private final static String PAPER_FEED_CUT	= "fP";	
	private final static String BITMAP			= "B";
	private final static String TOP_LOGO		= "tL";
	private final static String BOTTOM_LOGO		= "bL";
	private final static String MULTI_LINE_FEED	= "lF";
	private final static String ONE_LINE_FEED	= CharBuffer.wrap(LINEFEED_CH).toString();	
	private final static String BARCODE			= "R";
	private final static String SINGLE_SIZE		= "1C";
	private final static String DOUBLE_SIZE		= "2C";	
	private final static String DOUBLE_HEIGHT	= "3C";	
	private final static String DOUBLE_WIDTH_HEIGHT	= "4C";	
	
	private static CasioPrinter instance;
	
	private boolean mIsBusy = false;
	

	private LocalDevice mDeviceState = LocalDevice.CLOSE_STATE;

	public static CasioPrinter getInstance() {
		if (instance == null) {
			instance = new CasioPrinter();

		}
		return instance;
	}

	private LinePrinter lp;

	private BuildinEx840 lpd;

	private List<String> printContent;

	private Thread mPrintThread;

	private boolean mIsConnected;
	private boolean mIsEnable = false;


	private void sendToExPrinter(BuildinEx840 dev, byte[] inStr) {

		try {
			dev.write(inStr);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}


	@Override
	public LocalDevice getState() {
		// TODO Auto-generated method stub
		return mDeviceState;
	}

	@Override
	public void onDisconnect() {
		if (mDeviceState != LocalDevice.CLOSE_STATE) {

			if (lpd != null) {
				lpd.close(); // close device
			}
			if (lp != null) {
				lp.close(); // close line printer.
			}
			mDeviceState = LocalDevice.CLOSE_STATE;
			mIsConnected = false;
		}

	}

	@Override
	public void onConnect() {
		// TODO Auto-generated method stub

		if (mDeviceState != LocalDevice.OPEN_STATE) {
			lpd = new BuildinEx840();
			lp = new LinePrinter();
			printContent = new ArrayList<String>();
			reset();

			String sCountry = Locale.getDefault().getCountry();
			if (sCountry.equals(Locale.TRADITIONAL_CHINESE.getCountry())) {
				lpd.setMulticharMode(LinePrinterDeviceBase.MULTICHARMODE_BIG5);
			}else{
				lpd.setMulticharMode(LinePrinterDeviceBase.MULTICHARMODE_JISKANJI);
			}
			lpd.initCutter();
			lp.open(lpd);
			lpd.open();

			mDeviceState = LocalDevice.OPEN_STATE;
			mIsConnected = true;
		}

	}

	@Override
	public void setCallbackEvent(IDeviceEvent impl) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setComPort(int comPort) {
		// TODO Auto-generated method stub

	}

	@Override
	public void appendBuffer(String content) {
		printContent.add(ESC_BASE + SINGLE_SIZE+ content + "\n" );
	}
	
	
	public void appendBuffer(String content, int fontSize, int align) {

		String resultContent = "";
		String sizeStr = "";

		switch (fontSize) {
		case FONT_SINGLE_SIZE:
			sizeStr = ESC_BASE + SINGLE_SIZE;
			break;
		case FONT_DOUBLE_SIZE:
			sizeStr = ESC_BASE + DOUBLE_SIZE;
			break;
		case FONT_DOUBLE_HEIGHT:
			sizeStr = ESC_BASE + DOUBLE_HEIGHT;
			break;
		}
		
		int iLen = content.length();
		int i,j;
	
		i = iTotalLen;
		if(fontSize == FONT_DOUBLE_SIZE){
			i = iTotalLen / 2;
		}
		
		i = i - iLen;
		switch(align){
		case LEFT:
			resultContent = content.trim();
			break;
		case CENTER:
			i = i/2;
			resultContent = StringUtils.fillStringOnLeft(content, i, " ");
			break;
		case RIGHT:
			resultContent = StringUtils.fillStringOnLeft(content, i, " ");
			break;
		}

		printContent.add(sizeStr + resultContent + "\n");

	}
	
	public String toPrintContent(String content){
		return ESC_BASE + SINGLE_SIZE+ content + "\n" ;
	}
	public String toPrintContent(String content, int fontSize, int align) {

		String resultContent = "";
		String sizeStr = "";

		switch (fontSize) {
		case FONT_SINGLE_SIZE:
			sizeStr = ESC_BASE + SINGLE_SIZE;
			break;
		case FONT_DOUBLE_SIZE:
			sizeStr = ESC_BASE + DOUBLE_SIZE;
			break;
		case FONT_DOUBLE_HEIGHT:
			sizeStr = ESC_BASE + DOUBLE_HEIGHT;
			break;
		}
		
		int iLen = content.length();
		int i,j;
	
		i = iTotalLen;
		if(fontSize == FONT_DOUBLE_SIZE){
			i = iTotalLen / 2;
		}
		
		i = i - iLen;
		switch(align){
		case LEFT:
			resultContent = content.trim();
			break;
		case CENTER:
			i = i/2;
			resultContent = StringUtils.fillStringOnLeft(content, i, " ");
			break;
		case RIGHT:
			resultContent = StringUtils.fillStringOnLeft(content, i, " ");
			break;
		}

		return sizeStr + resultContent + "\n";

	}

	@Override
	public void clearBuffer() {
		// TODO Auto-generated method stub
		printContent = new ArrayList<String>();
	}

	@Override
	public void cutPaper() {
		// TODO Auto-generated method stub
		byte[] lfs = new byte[] { 0x1B, 'i' }; // Paper Cut
		sendToExPrinter(lpd, lfs);
	}

	@Override
	public int isReady() {
		// TODO Auto-generated method stub
		return 0;
	}
	
	
	/*
	
	@Override
	public void print() {
		if (mPrintThread == null) {
			mPrintThread = new Thread(new Runnable() {
				@Override
				public void run() {

					doPrint();

				}
			});

			mPrintThread.setDaemon(true);
			mPrintThread.start();
		}

		if (mPrintThread.getState() != Thread.State.TERMINATED) {

		} else {

			mPrintThread = new Thread(new Runnable() {
				@Override
				public void run() {

					doPrint();

				}
			});
			mPrintThread.setDaemon(true);
			mPrintThread.start();
		}
	
	}
	
	private void doPrint() {
		// TODO Auto-generated method stub
		try {
			lpd.init();
			
			for (int i = 0; i < printContent.size(); i++)
				lp.printNormal(printContent.get(i));

			byte[] lfs = new byte[] { 0x1B, 'd', 5 }; // Line feed
			sendToExPrinter(lpd, lfs);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		
	}
*/
	
	
	@Override
	public void print() {
		// TODO Auto-generated method stub
		mIsBusy = true;
		try {
			lpd.init();
			for (int i = 0; i < printContent.size(); i++)
				lp.printNormal(printContent.get(i));

			byte[] lfs = new byte[] { 0x1B, 'd', 5 }; // Line feed
			sendToExPrinter(lpd, lfs);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		mIsBusy = false;
		
	}
	
	@Override
	public void print(String text){
		mIsBusy = true;
		try {
			lpd.init();
		
			lp.printNormal(text);

			byte[] lfs = new byte[] { 0x1B, 'd', 5 }; // Line feed
			sendToExPrinter(lpd, lfs);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		mIsBusy = false;
	}
	
	public List<String> getBuffer() {
		// TODO Auto-generated method stub
		return this.printContent;
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void sendCmd(String strCommand) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean isBusy() {
		// TODO Auto-generated method stub
		return mIsBusy;
		//return true;
	}

	@Override
	public void onClearBuffer() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean isConnected() {
		// TODO Auto-generated method stub
		return mIsConnected;
	}


	@Override
	public void setEnable(boolean b) {
		mIsEnable  = b;
	}


	@Override
	public boolean getEnable() {
		return mIsEnable;
	}


	
}
